// delete 是显示禁用函数的语法机制，允许开发者主动阻止特定的拷贝构造函数或者赋值运算符被调用。
/*
实现单例模式：确保一个类只能有一个实例，可以删除拷贝构造函数和赋值操作符。

保证对象的移动语义：在现代C++中，为了支持移动语义，开发者可能会删除拷贝或赋值操作符，而提供移动构造函数和移动赋值操作符。

私有化特殊成员函数：将默认的特殊成员函数设为delete，可以防止编译器自动生成它们，这在某些需要完全控制对象生命周期的情况下很有用
*/

#include <iostream>

class Date{
public:
    Date() = default;            // 让编译其提供标准的默认行为  有了其他的构造函数就不会提供默认的构造函数
    Date(int year, int month, int day)
    {
        m_year = year;
        m_month = month;
        m_day = day;
    }
    explicit Date(int year) : m_year(year){}  //禁止隐式类型转换
    
    Date(int year, int month) : m_month(month), m_year(year){}
    Date operator=(Date&&){
        std::cout << "Date move operator" << std::endl;
        return *this;
    }
    Date(Date&&){
        std::cout << "Date move constructor" << std::endl;
    }
    Date (const Date& d){
        this->m_year = d.m_year;
        this->m_month = d.m_month;
        this->m_day = d.m_day;
        std::cout << "Date copy constructor" << std::endl;
    }
    Date& operator=(const Date& d){
        this->m_year = d.m_year;
        this->m_month = d.m_month;
        this->m_day = d.m_day;
        std::cout << "Date copy operator" << std::endl;
        return *this;
    }
    ~Date() = default;

    int m_year = 0;
    int m_month = 0;
    int m_day = 0;

    void print()
    {
        std::cout << m_year << "-" << m_month << "-" << m_day << std::endl;
    }
};

class NoCopy
{
public:
    NoCopy() = default;
    ~NoCopy() = default;

    NoCopy(const NoCopy&) = delete;      //删除拷贝构造函数
    NoCopy& operator=(const NoCopy&) = delete;   //删除赋值操作符号
};

void fun(Date d)
{
    std::cout << "Date" << std::endl;
}

Date fun2()
{
    Date d(2025, 1, 1);
    return d;
}   


int main()
{
    Date d1(2020, 1, 1);
    Date d2(2020);
    // 拷贝构造函数的场景
    // （1）用已经存在的对象初始化新对象
    Date d3(d1);
    std::cout << "d3 Date" << std::endl;
    d3.print();

    std::cout << "d4 Date" << std::endl;
    Date d4 = d1;
    //（2）对象作为值传递给函数
    std::cout << "fun Date" << std::endl;
    fun(d1);
    // (3)  对象作为返回值 可能会被编译器优化NRVO
    std::cout << "d5 Date" << std::endl;
    Date d5 = fun2();

    // 赋值运算符的调用场景
    //（1） 已经存在的对象间使用 = 操作符
    std::cout << "d6 Date" << std::endl;
    Date d6;
    d6 = d1;    
    d6.print();

    //禁止隐式类型转换
    // Date d7 = 2025;   //编译报错
    std::cout << "d8 Date" << std::endl;
    Date d8 = {2025, 1}; // 隐式类型转换

    std::cout << "d9 Date" << std::endl;
    Date d9 = std::move(d8);
    d9.print();

    d9 = fun2();

    std::cout << "d10 Date" << std::endl;
    Date d10 = fun2();  
    // NoCopy nc1;
    // NoCopy nc2 = nc1;    //编译报错
    // NoCopy nc3(nc1);


    return 0;
}